package cn.iocoder.yudao.module.member.service.order;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
import cn.iocoder.yudao.module.member.controller.admin.order.vo.AdminOrderPageVo;
import cn.iocoder.yudao.module.member.controller.admin.profit.vo.ProfitSaveReqVO;
import cn.iocoder.yudao.module.member.controller.admin.siteconfig.vo.MemberDeviceConfigVo;
import cn.iocoder.yudao.module.member.controller.app.order.vo.AppOrderPageVo;
import cn.iocoder.yudao.module.member.controller.app.order.vo.AppOrderVo;
import cn.iocoder.yudao.module.member.controller.app.order.vo.PriceVo;
import cn.iocoder.yudao.module.member.convert.order.MemberOrderConvert;
import cn.iocoder.yudao.module.member.dal.dataobject.order.MemberOrderDo;
import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO;
import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserExtendDO;
import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserPriceDetailDo;
import cn.iocoder.yudao.module.member.dal.mysql.order.MemberOrderMapper;
import cn.iocoder.yudao.module.member.dal.mysql.user.MemberUserMapper;
import cn.iocoder.yudao.module.member.dal.redis.no.OrderNoRedisDAO;
import cn.iocoder.yudao.module.member.enums.OrderStatusEnum;
import cn.iocoder.yudao.module.member.enums.OrderTypeEnum;
import cn.iocoder.yudao.module.member.enums.point.MemberPointBizTypeEnum;
import cn.iocoder.yudao.module.member.service.device.MemberDeviceRecordService;
import cn.iocoder.yudao.module.member.service.point.MemberPointRecordService;
import cn.iocoder.yudao.module.member.service.profit.ProfitService;
import cn.iocoder.yudao.module.member.service.siteconfiguration.MemBerDeviceConfigService;
import cn.iocoder.yudao.module.member.service.user.MemberUserExtendService;
import cn.iocoder.yudao.module.member.service.user.MemberUserPriceDetailService;
import cn.iocoder.yudao.module.member.service.user.MemberUserService;
import cn.iocoder.yudao.module.pay.api.order.PayOrderApi;
import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.addTime;
import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
import static cn.iocoder.yudao.module.member.enums.ErrorCodeConstants.*;
import static cn.iocoder.yudao.module.member.enums.profit.ProfitBizTypeEnum.ADD_CERTIFICATE_ORDER;
import static cn.iocoder.yudao.module.signature.enums.ErrorCodeConstants.APPLICATION_INFO_NOT_EXISTS;

@Service
@Validated
@Slf4j
public class OrderServiceImpl  implements OrderService{


    @Resource
    private MemberOrderMapper orderMapper;
    @Resource
    private MemberUserService memberUserService;
    @Resource
    private MemberUserExtendService memberUserExtendService;

    @Resource
    private MemberUserMapper memberUserMapper;
    @Resource
    private OrderNoRedisDAO orderNoRedisDAO;
    private final String ORDER = "order";
    private final String STANDARD_EDITION_CODE = "VT3";
    @Resource
    private MemberPointRecordService memberPointRecordService;
    @Resource
    private MemberDeviceRecordService memberDeviceRecordService;
    @Resource
    private PayOrderApi payOrderApi;
    @Resource
    private ProfitService profitService ;
    @Resource
    private MemBerDeviceConfigService memBerDeviceConfigService ;
    @Resource
    private MemberUserPriceDetailService memberUserPriceDetailService ;


    private static final String PAY_APP_KEY = "alipay_pc";
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createOrder(AppOrderVo appOrderVo) {
        Long userId = getLoginUserId();
        String orderCode = orderNoRedisDAO.generate(ORDER);
        appOrderVo.setUserId(userId);
        //如果是设备订单
        if("1".equals(appOrderVo.getOrderType())){
            PriceVo priceVo = checkPrice(appOrderVo);
            appOrderVo.setCostPrice(priceVo.getCostPrice());
        }
        MemberUserDO user = memberUserService.getUser(userId);
        //根据订单类型+支付类型判断是否需要扣减积分
        //1:积分购买设备数
        if("1".equals(appOrderVo.getOrderType()) && "0".equals(appOrderVo.getPaymentType())){

            MemberUserExtendDO userExtendDO = memberUserExtendService.getUserExtend(userId);
          if(userExtendDO.getTotalPoint().compareTo(appOrderVo.getPayPrice()) < 0)  {
//              throw new RuntimeException("积分不足");
              throw exception(USER_POINT_NOT_ENOUGH);
          }

            BigDecimal totalPointFront = userExtendDO.getTotalPoint();
            Integer totalDeviceFront = userExtendDO.getTotalDevice();
            userExtendDO.setTotalPoint(userExtendDO.getTotalPoint().subtract(appOrderVo.getPayPrice()));
            userExtendDO.setTotalDevice(userExtendDO.getTotalDevice() + appOrderVo.getNumber().intValue() );
            userExtendDO.setSpendingPower(userExtendDO.getSpendingPower().add(appOrderVo.getPayPrice()));
            log.info("充值设备数userId={}",userExtendDO.getUserId());
            memberUserExtendService.updateById(userExtendDO);
          //积分充足的情况需要扣减积分并添加设备与积分
            memberPointRecordService.createPointRecord(userId,appOrderVo.getPayPrice(), MemberPointBizTypeEnum.REDUCE_RECHARGE,appOrderVo.getOrderCode(),userExtendDO.getTotalPoint(),totalPointFront,null,null,null);
            memberDeviceRecordService.createDeviceRecord(userId,appOrderVo.getNumber().intValue(), MemberPointBizTypeEnum.ADD_DEVICE,appOrderVo.getOrderCode(),userExtendDO.getTotalDevice(),totalDeviceFront,null,null,null);
            appOrderVo.setStatus(OrderStatusEnum.COMPLETED.getCode());
            MemberOrderDo orderDo = MemberOrderConvert.INSTANCE.convert(appOrderVo);
            orderDo.setOrderCode(orderCode);
            orderDo.setUserId(userId);
            orderDo.setNickname(user.getNickname());
            orderMapper.insert(orderDo);
            return orderDo.getId();
        }else {
            //购买积分
            appOrderVo.setStatus(OrderStatusEnum.UNPAID.getCode());
        }

        MemberOrderDo orderDo = MemberOrderConvert.INSTANCE.convert(appOrderVo);
        orderDo.setOrderCode(orderCode);
        orderDo.setUserId(userId);
        orderDo.setNickname(user.getNickname());
//        orderDo.setPayPrice(orderDo.getPayPrice().multiply(BigDecimal.valueOf(100)));
        orderMapper.insert(orderDo);
        // 2.1 创建支付单
        Long payOrderId = payOrderApi.createOrder(new PayOrderCreateReqDTO()
                .setAppKey(PAY_APP_KEY).setUserIp(getClientIP()) // 支付应用
                .setMerchantOrderId(orderDo.getId().toString()) // 业务的订单编号
                .setSubject("价格").setBody("").setPrice(orderDo.getPayPrice().multiply(BigDecimal.valueOf(100))) // 价格信息
                .setExpireTime(addTime(Duration.ofHours(2L))));
        orderDo.setPayOrderId(payOrderId);
        orderMapper.updateById(orderDo);

      return payOrderId;
    }

    private PriceVo checkPrice(AppOrderVo appOrderVo) {

        List<MemberDeviceConfigVo> config = memBerDeviceConfigService.getConfig();
        MemberDeviceConfigVo memberDeviceConfigVo ;

        List<MemberUserPriceDetailDo> userByUserIds= memberUserPriceDetailService.getUserByUserId(appOrderVo.getUserId());
        MemberUserPriceDetailDo memberUserPriceDetailDo = userByUserIds.stream().filter(t -> "iphone".equals(t.getDeviceType()) && STANDARD_EDITION_CODE.equals(t.getVersionTypeCode()) && "0".equals(t.getPurchaseType())).findFirst().orElse(null);
        if (memberUserPriceDetailDo != null){
            //如果有单独的配置取单独配置
            PriceVo priceVo = new PriceVo();
            priceVo.setPrice(memberUserPriceDetailDo.getPrice().multiply(appOrderVo.getNumber()));
            appOrderVo.setPayPrice(priceVo.getPrice());
            priceVo.setCostPrice(memberUserPriceDetailDo.getCostPrice().multiply(appOrderVo.getNumber()));
            return priceVo;
        }
        //根据购买数量过滤
        memberDeviceConfigVo = config.stream().filter(t -> t.getDeviceNumber().compareTo(appOrderVo.getNumber())==0).findFirst().orElse(null);
        if (ObjectUtil.isNotEmpty(memberDeviceConfigVo)){
            PriceVo priceVo = new PriceVo();
            priceVo.setPrice(memberDeviceConfigVo.getPurchaseType());
            appOrderVo.setPayPrice(priceVo.getPrice());
            priceVo.setCostPrice(memberDeviceConfigVo.getPriceCost());
            return priceVo;
        }
        //没有对应的购买数量去配置为1 的价格
        if (memberDeviceConfigVo==null){
            memberDeviceConfigVo = config.stream().filter(t -> t.getDeviceNumber().compareTo(BigDecimal.ONE)==0).findFirst().orElse(null);
        }
        if (memberDeviceConfigVo==null){
            throw exception(DEVICE_EXISTS);
        }
        PriceVo priceVo = new PriceVo();
        priceVo.setPrice(memberDeviceConfigVo.getPrice().multiply(appOrderVo.getNumber()));
        appOrderVo.setPayPrice(priceVo.getPrice());
//        if (priceVo.getPrice().compareTo(appOrderVo.getPayPrice())!=0){
//            throw exception(DEVICE_PRICE_EXISTS);
//        }
        priceVo.setCostPrice(memberDeviceConfigVo.getPriceCost().multiply(appOrderVo.getNumber()));
        return priceVo;
    }

    @Override
    @Transactional
    public void updateWalletRechargerPaid(Long id, Long payOrderId) {
        // 1.1 获取钱包充值记录
        MemberOrderDo orderDo = orderMapper.selectById(id);
        if (orderDo == null) {
//            throw new RuntimeException("充值记录不存在");
            throw exception(USER_ORDER_NOT_EXISTS);
        }
        // 1.2 校验钱包充值是否可以支付
        if (!Objects.equals(orderDo.getStatus(), OrderStatusEnum.UNPAID.getCode())){
//            throw new RuntimeException("订单已完成");
            throw exception(USER_ORDER_STATUS);

        }
        //校验支付方式
        if ("0".equals(orderDo.getPaymentType())){
//            throw new RuntimeException("支付类型错误");
            throw exception(USER_ORDER_PAYMENT_TYPE);
        }

        //更新订单已完成
        orderDo.setStatus(OrderStatusEnum.COMPLETED.getCode());
        orderMapper.updateById(orderDo);
        //更新积分信息与设备信息
//        MemberUserDO user = memberUserService.getUser(orderDo.getUserId());
        MemberUserExtendDO userExtendDO = memberUserExtendService.getUserExtend(orderDo.getUserId());
        if (orderDo.getOrderType().equals(OrderTypeEnum.DEVICE.getCode())){
            Integer totalDeviceFront = userExtendDO.getTotalDevice();
            userExtendDO.setTotalDevice(userExtendDO.getTotalDevice() + orderDo.getNumber().intValue() );
            //积分充足的情况需要扣减积分并添加设备与积分
            memberDeviceRecordService.createDeviceRecord(orderDo.getUserId(),orderDo.getNumber().intValue(), MemberPointBizTypeEnum.ADD_DEVICE,orderDo.getOrderCode(),userExtendDO.getTotalDevice(),totalDeviceFront,null,null,null);
            //购买设备需要记录利润
            Date date = new Date();
            ProfitSaveReqVO profitSaveReqVO = new ProfitSaveReqVO();
            profitSaveReqVO.setType(ADD_CERTIFICATE_ORDER.getType());
            profitSaveReqVO.setPrice(orderDo.getPayPrice());
            profitSaveReqVO.setCostPrice(orderDo.getCostPrice());
            profitSaveReqVO.setProfit(orderDo.getPayPrice().subtract(orderDo.getCostPrice()));
            profitSaveReqVO.setYear(DateUtil.year(date));
            profitSaveReqVO.setMonth(DateUtil.month(date));
            profitService.createProfit(profitSaveReqVO);

        }else if (orderDo.getOrderType().equals(OrderTypeEnum.POINT.getCode())){
            BigDecimal totalPointFront = userExtendDO.getTotalPoint();
            userExtendDO.setTotalPoint(userExtendDO.getTotalPoint().add(orderDo.getPayPrice()));
            memberPointRecordService.createPointRecord(orderDo.getUserId()  ,orderDo.getPayPrice(), MemberPointBizTypeEnum.ADD_RECHARGE,orderDo.getOrderCode(),userExtendDO.getTotalPoint(),totalPointFront,null,null,null);
        }
        log.info("充值信息回调userId={}",userExtendDO.getUserId());
        memberUserExtendService.updateById(userExtendDO);
    }

    @Override
    public PageResult<MemberOrderDo> getRecordPage(Long loginUserId, AppOrderPageVo pageReqVO) {
        return  orderMapper.selectPage(loginUserId, pageReqVO);
    }

    @Override
    public PageResult<MemberOrderDo> getRecordPage(AdminOrderPageVo pageReqVO) {

        if (StrUtil.isNotEmpty(pageReqVO.getNickName())){
            List<MemberUserDO> userListByNickname = memberUserService.getUserListByNickname(pageReqVO.getNickName());
            if(CollectionUtils.isEmpty(userListByNickname)){
                return PageResult.empty();
            }
            pageReqVO.setIds(userListByNickname.stream().map(MemberUserDO::getId).collect(Collectors.toList()));
        }
        PageResult<MemberOrderDo> memberOrderDoPageResult = orderMapper.selectPageAdmin(pageReqVO);
        if (!CollectionUtils.isEmpty(memberOrderDoPageResult.getList())){
            List<Long> collect = memberOrderDoPageResult.getList().stream().map(MemberOrderDo::getUserId).collect(Collectors.toList());
            List<MemberUserDO> userList = memberUserService.getUserList(collect);
            memberOrderDoPageResult.getList().forEach(memberOrderDo -> {
                userList.stream().filter(user -> Objects.equals(user.getId(), memberOrderDo.getUserId())).findFirst().ifPresent(user -> memberOrderDo.setNickname(user.getNickname()));
            });
        }
        return  memberOrderDoPageResult;
    }


}
